package cn.zswltech.gruul.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * @Author: Jason
 * @Date: 2019/4/24 上午11:30
 */
public class ObjectUtil {
    /**
     * 通过反射拷贝两个对象的同名同类型变量,包括父类
     *
     * @param src
     * @param target
     */
    public static void copyFieldValue(Object src, Object target) {
        if (src == null || target == null) {
            return;
        }
        copyFields(src, target, null);
    }

    /**
     * 复制字段的值
     *
     * @param source         源对象
     * @param target         目标对象
     * @param skipFieldNames 过滤的字段
     */
    public static void copyFields(Object source, Object target, String[] skipFieldNames) {
        Set<String> skips = new HashSet<>();
        if (skipFieldNames != null) {
            skips.addAll(Arrays.asList(skipFieldNames));
        }
        HashMap<String, Field> sourceFieldMap = getFields(source);
        HashMap<String, Field> targetFieldMap = getFields(target);
        sourceFieldMap.forEach((key, sourceField) -> {
            sourceField.setAccessible(true);
            try {
                if (sourceField.get(source) != null && !skips.contains(key) && targetFieldMap.containsKey(key)) {
                    Field targetField = targetFieldMap.get(key);
                    // 类型必须一致
                    if (!sourceField.getType().equals(targetField.getType())) {
                        return;
                    }
                    targetField.setAccessible(true);
                    targetField.set(target, sourceField.get(source));
                }
            } catch (IllegalAccessException e) {
                // 已经设置过访问权限，不会抛出此异常
            }
        });
    }

    /**
     * 获取对象所有的字段(不含final类型),包括父类
     *
     * @param obj 对象
     * @return 字段名与Field对象的映射map
     */
    private static HashMap<String, Field> getFields(Object obj) {
        Class sourceClass = obj.getClass();
        //获取对象所有字段 包括父类
        ArrayList<Field> sourceFields = new ArrayList<>();
        while (sourceClass != null) {
            sourceFields.addAll(Arrays.asList(sourceClass.getDeclaredFields()));
            sourceClass = sourceClass.getSuperclass();
        }
        //字段名去重
        HashMap<String, Field> sourceFieldMap = new HashMap<>();
        for (Field field : sourceFields) {
            // 过滤不需要拷贝的属性
            if (Modifier.isFinal(field.getModifiers())) {
                continue;
            }
            sourceFieldMap.put(field.getName(), field);
        }
        return sourceFieldMap;
    }
}
